<template>
  <PageWrapper title="学习表单的使用">
    <template #headerContent>
      <a-button @click="handleGetFieldsValue">获取表单数据</a-button>
      <a-button @click="validateForm" class="ml-2">手动校验表单</a-button>
      <a-button @click="resetValidate" class="ml-2">重置校验信</a-button>
      <a-button @click="setFormValues" class="ml-2">设置表单值</a-button>
      <a-button @click="resetFields" class="ml-2">重置</a-button>
    </template>
    <CollapseContainer title="Form案例">
      <BasicForm @register="register" @submit="handleSubmit">
        <template #formHeader>
          <Alert class="!block" message="我是表单顶部区域的插槽" />
        </template>

        <template #formFooter>
          <Alert class="!block" message="我是表单底部区域的插槽" />
        </template>

        <!-- slot 自定义渲染内容 日期1 -->
        <template #customDatePickerField="{ model, field }">
          <DatePicker :style="{ width: '100%' }" v-model:value="model[field]" />
        </template>
      </BasicForm>
    </CollapseContainer>

    <Test />
    <!-- <Time /> -->
  </PageWrapper>
</template>

<script lang="tsx" setup>
  import { Alert, DatePicker, Select } from 'ant-design-vue';
  import { PageWrapper } from '/@/components/Page';
  import { CollapseContainer } from '/@/components/Container';
  import { BasicForm, FormSchema, useForm } from '/@/components/Form/index';
  import { computed, nextTick, ref, unref } from 'vue';
  import { Moment } from 'moment';
  import { cloneDeep } from 'lodash-es';
  import { optionsListApi } from '/@/api/demo/select';
  import { areaRecord } from '/@/api/demo/cascader';
  import { useMessage } from '/@/hooks/web/useMessage';
  import Test from './TestCmp.vue';
  // import { Time } from '/@/components/Time';

  const { createMessage } = useMessage();

  const mutexSelectOptions = Array.from({ length: 10 }).map((v, i) => ({
    label: '选项' + (i + 1),
    value: i,
  })) as Recordable[];

  const mutexSelectAValue = ref<number[]>([]);
  const mutexSelectBValue = ref<number[]>([]);
  const mutexSelectAOptions = computed(() => {
    return cloneDeep(mutexSelectOptions).map((v) => {
      v.disabled = unref(mutexSelectBValue).indexOf(v.value) > -1;
      return v;
    });
  });
  const mutexSelectBOptions = computed(() => {
    return cloneDeep(mutexSelectOptions).map((v) => {
      v.disabled = unref(mutexSelectAValue).indexOf(v.value) > -1;
      return v;
    });
  });

  const basicCmpFormSchemas: FormSchema[] = [
    {
      field: 'divider1',
      component: 'Divider',
      label: '基础组件',
      colProps: {
        sm: 24,
        md: 24,
        lg: 24,
        xl: 24,
      },
    },
    {
      field: 'name',
      component: 'Input',
      label: '姓名',
      defaultValue: '',
      helpMessage: '需要您输入您的姓名',
      componentProps: {
        placeholder: '请输入姓名',
        onChange(e: ChangeEvent) {
          console.log(e.target.value);
        },
      },
    },
    {
      field: 'nickname',
      component: 'Input',
      label: '昵称',
      // render函数形式渲染对应组件的插槽内容
      renderComponentContent() {
        return {
          prefix: () => '前缀',
          suffix: () => '后缀',
        };
      },
      componentProps: {
        onChange: (e: any) => {
          console.log(e);
        },
      },
    },
    {
      field: 'testname1',
      component: 'Input',
      label: '测试过滤空格',
      componentProps({ formModel }) {
        // 需要注意的是：当FormSchema中对应的组件没有默认值时formModel中是不会显示对应field的字段的
        return {
          // 此处想要获取formModel中存储的字段值需要等待dom更新完成后才可以获取
          // 还有一点：
          async onChange() {
            await nextTick();
            // 在此处对input的值做操作
            formModel.testname1 = formModel.testname1.trim();
          },
        };
      },
    },
    {
      field: 'date1',
      component: 'DatePicker',
      label: '日期1',
      slot: 'customDatePickerField',
    },
    {
      field: 'date2',
      label: '日期范围选择2',
      component: 'RangePicker',
      helpMessage: '设置DatePicker宽度与值的格式化',
      componentProps: {
        valueFormat: 'YYYY-MM-DD',
        // 设置组件的样式
        style: {
          width: '100%',
        },
      },
    },
    {
      field: 'date3',
      label: '日期范围选择3',
      component: 'RangePicker',
      helpMessage: '将表单内时间区域的值映射成2个字段',
      componentProps: {
        style: {
          width: '100%',
        },
      },
    },
    {
      field: 'date4',
      label: '日期范围选择4',
      component: 'RangePicker',
      helpMessage: '将开始与结束时间处理成每天的最开始时间和最后一刻',
      componentProps({ formModel }) {
        return {
          style: {
            width: '100%',
          },
          // eslint-disable-next-line @typescript-eslint/no-unused-vars
          async onChange(value: Moment[]) {
            if (value.length === 0) {
              return;
            }
            await nextTick();
            formModel.date4 = [value[0].startOf('date'), value[1].endOf('date')];
          },
        };
      },
    },
    {
      field: 'select1',
      label: '选择项1',
      component: 'Select',
      componentProps: {
        style: {
          width: '100%',
        },
        options: [
          {
            label: '选项1',
            value: 0,
          },
          {
            label: '选项2',
            value: 1,
          },
        ],
      },
    },
    {
      field: 'checkbox1',
      label: '复选框',
      component: 'CheckboxGroup',
      componentProps: {
        options: [
          {
            label: '选项1',
            value: 0,
          },
          {
            label: '选项2',
            value: 1,
          },
        ],
      },
    },
    {
      field: 'radio1',
      label: '复选框',
      component: 'RadioGroup',
      componentProps: {
        options: [
          {
            label: '选项1',
            value: 0,
          },
          {
            label: '选项2',
            value: 1,
          },
        ],
      },
    },
    {
      field: 'switch1',
      component: 'Switch',
      label: 'Switch',
      defaultValue: true,
      helpMessage: '切换Switch，控制后面一列的显示与隐藏',
      componentProps() {
        return {
          onChange(value) {
            console.log(value);
          },
        };
      },
    },
    {
      field: 'relationSwitch1',
      component: 'Input',
      label: '关联Switch',
      helpMessage: '根据Switch的值显示与隐藏',
      // 每当form里的组件值更新时 方法都会被重新执行
      show({ values }) {
        return values.switch1;
      },
    },
    {
      field: 'divider2',
      component: 'Divider',
      label: '互斥多选',
      helpMessage: ['两个Select共用数据源', '但不可选择对方已选中的项目'],
      colProps: {
        sm: 24,
        md: 24,
        lg: 24,
        xl: 24,
      },
    },
    {
      field: 'mutexSelect1',
      component: 'Select',
      label: '互斥SelectA',
      defaultValue: [],
      render({ model, field }) {
        return (
          <Select
            mode="multiple"
            options={mutexSelectAOptions.value}
            v-model={[model[field], 'value']}
            onChange={() => (mutexSelectAValue.value = model[field])}
          />
        );
      },
    },
    {
      field: 'mutexSelectB',
      component: 'Select',
      label: '互斥SelectB',
      defaultValue: [],
      render({ model, field }) {
        return (
          <Select
            mode="multiple"
            options={mutexSelectBOptions.value}
            v-model={[model[field], 'value']}
            onChange={() => (mutexSelectBValue.value = model[field])}
          />
        );
      },
    },
  ];

  const provincesOptions = [
    {
      id: 'guangdong',
      label: '广东省',
      value: '1',
    },
    {
      id: 'jiangsu',
      label: '江苏省',
      value: '2',
    },
  ];

  const citiesOptionsData = {
    guangdong: [
      {
        label: '珠海市',
        value: '1',
        key: '1',
      },
      {
        label: '深圳市',
        value: '2',
        key: '2',
      },
      {
        label: '广州市',
        value: '3',
        key: '3',
      },
    ],
    jiangsu: [
      {
        label: '南京市',
        value: '1',
        key: '1',
      },
      {
        label: '无锡市',
        value: '2',
        key: '2',
      },
      {
        label: '苏州市',
        value: '3',
        key: '3',
      },
    ],
  };

  const apiCmpFormSchemas: FormSchema[] = [
    {
      field: 'divider3',
      component: 'Divider',
      label: '通过接口获取数据',
      colProps: {
        sm: 24,
        md: 24,
        lg: 24,
        xl: 24,
      },
    },
    {
      field: 'asyncSelect1',
      component: 'ApiSelect',
      label: '远程下拉',
      defaultValue: '0',
      componentProps: {
        api: optionsListApi,
        // 取从接口返回的对象中的哪个字段
        resultField: 'list',
        // label 取值字段
        labelField: 'name',
        // value 取值字段
        valueField: 'id',
        // 是否立即加载数据（false:只有点开时才会加载数据）
        immediate: true,
        // 对接口返回的数据进行二次修改
        apiTransformResponse(res) {
          console.log('asyncSelect1 apiTransformResponse res', res);
          return res.map((v) => {
            v.customStr = '自定义值';
            return v;
          });
        },
        // 请求完成的回调函数
        onOptionsChange(res) {
          console.log('asyncSelect1 onOptionsChange res', res);
        },
      },
    },
    {
      field: 'cascaderField',
      component: 'ApiCascader',
      label: '级联远程加载',
      componentProps: {
        api: areaRecord,
        apiParamKey: 'parentCode',
        labelField: 'name',
        valueField: 'code',
        initFetchParams: {
          parentCode: '',
        },
        isLeaf(record) {
          return record.levelType >= 3;
        },
      },
    },
    {
      field: 'divider4',
      component: 'Divider',
      label: '字段联动',
      colProps: {
        sm: 24,
        md: 24,
        lg: 24,
        xl: 24,
      },
    },
    {
      field: 'province',
      component: 'Select',
      label: '省份',
      componentProps({ formModel, formActionType }) {
        return {
          options: provincesOptions,
          placeholder: '省份与城市联动',
          onChange(e, options) {
            let cityOptions;
            if (!e) {
              cityOptions = [];
            } else {
              cityOptions = citiesOptionsData[options.id];
            }
            formModel.city = undefined; //  reset city value
            formActionType.updateSchema({
              field: 'city',
              componentProps: {
                options: cityOptions,
              },
            });
          },
        };
      },
    },
    {
      field: 'city',
      component: 'Select',
      label: '城市',
      componentProps: {
        options: [],
        placeholder: '省份与城市联动',
      },
    },
  ];

  const validatorCmpFormSchemas: FormSchema[] = [
    {
      field: 'divider5',
      component: 'Divider',
      label: '表单验证',
      colProps: {
        sm: 24,
        md: 24,
        lg: 24,
        xl: 24,
      },
    },
    {
      field: 'validatorInputField1',
      component: 'Input',
      label: '字段1',
      helpMessage: '必填',
      required: true,
      // 需要注意的是：即使当前项不展示校验时也会把当前项包含进去
      // show: false,
    },
    {
      field: 'validatorSelectField2',
      label: '字段2',
      component: 'Select',
      componentProps: {
        style: {
          width: '100%',
        },
        options: [
          {
            label: '选项1',
            value: 0,
          },
          {
            label: '选项2',
            value: 1,
          },
        ],
      },
      rules: [{ required: true, message: '请选择当前项', type: 'number' }],
    },
    {
      field: 'validatorInputCountDownField3',
      component: 'InputCountDown',
      label: '验证码',
      required: true,
    },
    {
      field: 'validatorSelectField4',
      component: 'Select',
      label: '多选',
      colProps: {
        span: 8,
      },
      componentProps: {
        mode: 'multiple',
        options: [
          {
            label: '选项1',
            value: '1',
            key: '1',
          },
          {
            label: '选项2',
            value: '2',
            key: '2',
          },
        ],
      },
      rules: [
        {
          required: true,
          message: '当前项不可为空哦',
          type: 'array',
        },
      ],
    },
    {
      field: 'validatorCustomField5',
      label: '自定义校验',
      component: 'Input',
      rules: [
        {
          max: 16,
          min: 6,
          message: '内容长度为6~16',
          required: true,
        },
        {
          async validator(rule, value) {
            if (!value) {
              // 触发自定义校验时 移除上一条可能被触发过的错误信息
              return Promise.reject('值不能为空');
            }
            if (/[\-.,!`~——=+#@%$&:]/.test(value)) {
              return Promise.reject('请勿输入特殊字符');
            }
            return Promise.resolve();
          },
          trigger: 'change',
        },
      ],
    },
  ];

  const formSchemas: FormSchema[] = [
    ...basicCmpFormSchemas,
    ...apiCmpFormSchemas,
    ...validatorCmpFormSchemas,
  ];

  const [register, { getFieldsValue, validateFields, clearValidate, setFieldsValue, resetFields }] =
    useForm({
      labelWidth: 120,
      schemas: formSchemas,
      fieldMapToTime: [
        // 支持将多个时间范围选择器映射成两个字段
        // 调用getFieldsValue返回的时间格式化的值是YYYY-MM-DD HH:mm:ss形式
        ['date3', ['startTime', 'endTime'], 'YYYY-MM-DD'],
        ['date4', ['startTime2', 'endTime2'], 'YYYY-MM-DD HH:mm:ss'],
      ],
      // column的通用配置
      baseColProps: {
        sm: 24,
        md: 12,
        lg: 8,
        xl: 8,
      },
      rowProps: {
        gutter: 16,
      },
      actionColOptions: {
        span: 24,
        // sm: 24,
        // md: 12,
        // lg: 8,
        // xl: 8,
        // contentStyle: {
        //   paddingLeft: '120px',
        //   textAlign: 'left',
        // },
      },
    });

  // 通过getFieldsValue去表单的值时如果没有操作对应的控件或者没有默认值getFieldsValue方法返回的对象是没有对应field字段的（需要设置默认值，取值不可为null或undefined）
  function handleGetFieldsValue() {
    console.log(getFieldsValue());
  }

  // 提交
  function handleSubmit(values) {
    createMessage.info('请打开控制台查看提交的信息');
    console.log(values);
  }

  // 手动校验表单
  async function validateForm() {
    try {
      createMessage.info('请打开控制台查看校验的信息');
      const res = await validateFields();
      console.log('validateForm data', res);
    } catch (error) {
      console.log('validateForm error', error);
    }
  }

  function resetValidate() {
    clearValidate();
  }

  function setFormValues() {
    setFieldsValue({
      validatorInputField1: 'validatorInputField1',
      validatorSelectField2: 0,
      validatorSelectField4: ['1', '2'],
      validatorCustomField5: '123456#%',
    });
  }
</script>

<style>
  /**
    * 对antd中form配置参数 labelCol和wrapperCol的说明
    *
    * const labelCol = { span: 4, offset: 2 };
    * labelCol 顾名思义是对form label的设置
    * span: 表示的是在24列中占多数列，
    * offset: 表示label的左偏移多少列，实际体现在页面上就是label的margin-left设置多少值
    *
    * const wrapperCol = { span: 10, offset: 1 };
    * wrapperCol是对label的右侧（可能不在后侧，可能在下一行）表单控件中的主体区域的设置，其参数与作用于labelCol相同
  */
</style>
